home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / g_missile.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  11.5 KB  |  435 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. #include "g_local.h"
  4.  
  5. #define    MISSILE_PRESTEP_TIME    50
  6.  
  7. /*
  8. ================
  9. G_BounceMissile
  10.  
  11. ================
  12. */
  13. void G_BounceMissile( gentity_t *ent, trace_t *trace ) {
  14.     vec3_t    velocity;
  15.     float    dot;
  16.     int        hitTime;
  17.  
  18.     // reflect the velocity on the trace plane
  19.     hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
  20.     BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
  21.     dot = DotProduct( velocity, trace->plane.normal );
  22.     VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
  23.  
  24.     if ( ent->s.eFlags & EF_BOUNCE_HALF ) {
  25.         VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
  26.         // check for stop
  27.         if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) {
  28.             G_SetOrigin( ent, trace->endpos );
  29.             return;
  30.         }
  31.     }
  32.  
  33.     VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
  34.     VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
  35.     ent->s.pos.trTime = level.time;
  36. }
  37.  
  38.  
  39. /*
  40. ================
  41. G_MissileImpact
  42.  
  43. ================
  44. */
  45. void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
  46.     gentity_t        *other;
  47.     qboolean        hitClient = qfalse;
  48.  
  49.     other = &g_entities[trace->entityNum];
  50.  
  51.     // check for bounce
  52.     if ( !other->takedamage &&
  53.         ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
  54.         G_BounceMissile( ent, trace );
  55.         G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
  56.         return;
  57.     }
  58.  
  59.     // impact damage
  60.     if (other->takedamage) {
  61.         // FIXME: wrong damage direction?
  62.         if ( ent->damage ) {
  63.             vec3_t    velocity;
  64.  
  65.             if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
  66.                 g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++;
  67.                 hitClient = qtrue;
  68.             }
  69.             BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
  70.             if ( VectorLength( velocity ) == 0 ) {
  71.                 velocity[2] = 1;    // stepped on a grenade
  72.             }
  73.             G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
  74.                 ent->s.origin, ent->damage, 
  75.                 0, ent->methodOfDeath);
  76.         }
  77.     }
  78.  
  79.     if (!strcmp(ent->classname, "hook")) {
  80.         gentity_t *nent;
  81.         vec3_t v;
  82.  
  83.         nent = G_Spawn();
  84.         if ( other->takedamage && other->client ) {
  85.  
  86.             G_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
  87.             nent->s.otherEntityNum = other->s.number;
  88.  
  89.             ent->enemy = other;
  90.  
  91.             v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;
  92.             v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;
  93.             v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;
  94.  
  95.             SnapVectorTowards( v, ent->s.pos.trBase );    // save net bandwidth
  96.         } else {
  97.             VectorCopy(trace->endpos, v);
  98.             G_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
  99.             ent->enemy = NULL;
  100.         }
  101.  
  102.         SnapVectorTowards( v, ent->s.pos.trBase );    // save net bandwidth
  103.  
  104.         nent->freeAfterEvent = qtrue;
  105.         // change over to a normal entity right at the point of impact
  106.         nent->s.eType = ET_GENERAL;
  107.         ent->s.eType = ET_GRAPPLE;
  108.  
  109.         G_SetOrigin( ent, v );
  110.         G_SetOrigin( nent, v );
  111.  
  112.         ent->think = Weapon_HookThink;
  113.         ent->nextthink = level.time + FRAMETIME;
  114.  
  115.         ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;
  116.         VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
  117.  
  118.         trap_LinkEntity( ent );
  119.         trap_LinkEntity( nent );
  120.  
  121.         return;
  122.     }
  123.  
  124.     // is it cheaper in bandwidth to just remove this ent and create a new
  125.     // one, rather than changing the missile into the explosion?
  126.  
  127.     if ( other->takedamage && other->client ) {
  128.         G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
  129.         ent->s.otherEntityNum = other->s.number;
  130.     } else {
  131.         G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
  132.     }
  133.  
  134.     ent->freeAfterEvent = qtrue;
  135.  
  136.     // change over to a normal entity right at the point of impact
  137.     ent->s.eType = ET_GENERAL;
  138.  
  139.     SnapVectorTowards( trace->endpos, ent->s.pos.trBase );    // save net bandwidth
  140.  
  141.     G_SetOrigin( ent, trace->endpos );
  142.  
  143.     // splash damage (doesn't apply to person directly hit)
  144.     if ( ent->splashDamage ) {
  145.         if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, 
  146.             other, ent->splashMethodOfDeath ) ) {
  147.             if( !hitClient ) {
  148.                 g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++;
  149.             }
  150.         }
  151.     }
  152.  
  153.     trap_LinkEntity( ent );
  154. }
  155.  
  156. /*
  157. ================
  158. G_ExplodeMissile
  159.  
  160. Explode a missile without an impact
  161. ================
  162. */
  163. void G_ExplodeMissile( gentity_t *ent ) {
  164.     vec3_t        dir;
  165.     vec3_t        origin;
  166.  
  167.     BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
  168.     SnapVector( origin );
  169.     G_SetOrigin( ent, origin );
  170.  
  171.     // we don't have a valid direction, so just point straight up
  172.     dir[0] = dir[1] = 0;
  173.     dir[2] = 1;
  174.  
  175.     ent->s.eType = ET_GENERAL;
  176.     G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
  177.  
  178.     ent->freeAfterEvent = qtrue;
  179.  
  180.     // splash damage
  181.     if ( ent->splashDamage ) {
  182.         if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, NULL
  183.             , ent->splashMethodOfDeath ) ) {
  184.             g_entities[ent->r.ownerNum].client->ps.persistant[PERS_ACCURACY_HITS]++;
  185.         }
  186.     }
  187.  
  188.     trap_LinkEntity( ent );
  189. }
  190.  
  191.  
  192. /*
  193. ================
  194. G_RunMissile
  195.  
  196. ================
  197. */
  198. void G_RunMissile( gentity_t *ent ) {
  199.     vec3_t        origin;
  200.     trace_t        tr;
  201.  
  202.     // get current position
  203.     BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
  204.  
  205.     // trace a line from the previous position to the current position,
  206.     // ignoring interactions with the missile owner
  207.     trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, 
  208.         ent->r.ownerNum, ent->clipmask );
  209.  
  210.     VectorCopy( tr.endpos, ent->r.currentOrigin );
  211.  
  212.     if ( tr.startsolid ) {
  213.         tr.fraction = 0;
  214.     }
  215.  
  216.     trap_LinkEntity( ent );
  217.  
  218.     if ( tr.fraction != 1 ) {
  219.         // never explode or bounce on sky
  220.         if ( tr.surfaceFlags & SURF_NOIMPACT ) {
  221.             // If grapple, reset owner
  222.             if (ent->parent && ent->parent->client->hook == ent)
  223.                 ent->parent->client->hook = NULL;
  224.             G_FreeEntity( ent );
  225.             return;
  226.         }
  227.  
  228.         G_MissileImpact( ent, &tr );
  229.         if ( ent->s.eType != ET_MISSILE ) {
  230.             return;        // exploded
  231.         }
  232.     }
  233.  
  234.     // check think function after bouncing
  235.     G_RunThink( ent );
  236. }
  237.  
  238.  
  239. //=============================================================================
  240.  
  241. /*
  242. =================
  243. fire_plasma
  244.  
  245. =================
  246. */
  247. gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t dir) {
  248.     gentity_t    *bolt;
  249.  
  250.     VectorNormalize (dir);
  251.  
  252.     bolt = G_Spawn();
  253.     bolt->classname = "plasma";
  254.     bolt->nextthink = level.time + 10000;
  255.     bolt->think = G_ExplodeMissile;
  256.     bolt->s.eType = ET_MISSILE;
  257.     bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
  258.     bolt->s.weapon = WP_PLASMAGUN;
  259.     bolt->r.ownerNum = self->s.number;
  260.     bolt->parent = self;
  261.     bolt->damage = 20;
  262.     bolt->splashDamage = 15;
  263.     bolt->splashRadius = 20;
  264.     bolt->methodOfDeath = MOD_PLASMA;
  265.     bolt->splashMethodOfDeath = MOD_PLASMA_SPLASH;
  266.     bolt->clipmask = MASK_SHOT;
  267.  
  268.     bolt->s.pos.trType = TR_LINEAR;
  269.     bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;        // move a bit on the very first frame
  270.     VectorCopy( start, bolt->s.pos.trBase );
  271.     VectorScale( dir, 2000, bolt->s.pos.trDelta );
  272.     SnapVector( bolt->s.pos.trDelta );            // save net bandwidth
  273.  
  274.     VectorCopy (start, bolt->r.currentOrigin);
  275.  
  276.     return bolt;
  277. }    
  278.  
  279. //=============================================================================
  280.  
  281.  
  282. /*
  283. =================
  284. fire_grenade
  285. =================
  286. */
  287. gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) {
  288.     gentity_t    *bolt;
  289.  
  290.     VectorNormalize (dir);
  291.  
  292.     bolt = G_Spawn();
  293.     bolt->classname = "grenade";
  294.     bolt->nextthink = level.time + 2500;
  295.     bolt->think = G_ExplodeMissile;
  296.     bolt->s.eType = ET_MISSILE;
  297.     bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
  298.     bolt->s.weapon = WP_GRENADE_LAUNCHER;
  299.     bolt->s.eFlags = EF_BOUNCE_HALF;
  300.     bolt->r.ownerNum = self->s.number;
  301.     bolt->parent = self;
  302.     bolt->damage = 100;
  303.     bolt->splashDamage = 100;
  304.     bolt->splashRadius = 150;
  305.     bolt->methodOfDeath = MOD_GRENADE;
  306.     bolt->splashMethodOfDeath = MOD_GRENADE_SPLASH;
  307.     bolt->clipmask = MASK_SHOT;
  308.  
  309.     bolt->s.pos.trType = TR_GRAVITY;
  310.     bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;        // move a bit on the very first frame
  311.     VectorCopy( start, bolt->s.pos.trBase );
  312.     VectorScale( dir, 700, bolt->s.pos.trDelta );
  313.     SnapVector( bolt->s.pos.trDelta );            // save net bandwidth
  314.  
  315.     VectorCopy (start, bolt->r.currentOrigin);
  316.  
  317.     return bolt;
  318. }
  319.  
  320. //=============================================================================
  321.  
  322.  
  323. /*
  324. =================
  325. fire_bfg
  326. =================
  327. */
  328. gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir) {
  329.     gentity_t    *bolt;
  330.  
  331.     VectorNormalize (dir);
  332.  
  333.     bolt = G_Spawn();
  334.     bolt->classname = "bfg";
  335.     bolt->nextthink = level.time + 10000;
  336.     bolt->think = G_ExplodeMissile;
  337.     bolt->s.eType = ET_MISSILE;
  338.     bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
  339.     bolt->s.weapon = WP_BFG;
  340.     bolt->r.ownerNum = self->s.number;
  341.     bolt->parent = self;
  342.     bolt->damage = 100;
  343.     bolt->splashDamage = 100;
  344.     bolt->splashRadius = 120;
  345.     bolt->methodOfDeath = MOD_BFG;
  346.     bolt->splashMethodOfDeath = MOD_BFG_SPLASH;
  347.     bolt->clipmask = MASK_SHOT;
  348.  
  349.     bolt->s.pos.trType = TR_LINEAR;
  350.     bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;        // move a bit on the very first frame
  351.     VectorCopy( start, bolt->s.pos.trBase );
  352.     VectorScale( dir, 2000, bolt->s.pos.trDelta );
  353.     SnapVector( bolt->s.pos.trDelta );            // save net bandwidth
  354.     VectorCopy (start, bolt->r.currentOrigin);
  355.  
  356.     return bolt;
  357. }
  358.  
  359. //=============================================================================
  360.  
  361.  
  362. /*
  363. =================
  364. fire_rocket
  365. =================
  366. */
  367. gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir) {
  368.     gentity_t    *bolt;
  369.  
  370.     VectorNormalize (dir);
  371.  
  372.     bolt = G_Spawn();
  373.     bolt->classname = "rocket";
  374.     bolt->nextthink = level.time + 10000;
  375.     bolt->think = G_ExplodeMissile;
  376.     bolt->s.eType = ET_MISSILE;
  377.     bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
  378.     bolt->s.weapon = WP_ROCKET_LAUNCHER;
  379.     bolt->r.ownerNum = self->s.number;
  380.     bolt->parent = self;
  381.     bolt->damage = 100;
  382.     bolt->splashDamage = 100;
  383.     bolt->splashRadius = 120;
  384.     bolt->methodOfDeath = MOD_ROCKET;
  385.     bolt->splashMethodOfDeath = MOD_ROCKET_SPLASH;
  386.     bolt->clipmask = MASK_SHOT;
  387.  
  388.     bolt->s.pos.trType = TR_LINEAR;
  389.     bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;        // move a bit on the very first frame
  390.     VectorCopy( start, bolt->s.pos.trBase );
  391.     VectorScale( dir, 900, bolt->s.pos.trDelta );
  392.     SnapVector( bolt->s.pos.trDelta );            // save net bandwidth
  393.     VectorCopy (start, bolt->r.currentOrigin);
  394.  
  395.     return bolt;
  396. }
  397.  
  398. /*
  399. =================
  400. fire_grapple
  401. =================
  402. */
  403. gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir) {
  404.     gentity_t    *hook;
  405.  
  406.     VectorNormalize (dir);
  407.  
  408.     hook = G_Spawn();
  409.     hook->classname = "hook";
  410.     hook->nextthink = level.time + 10000;
  411.     hook->think = Weapon_HookFree;
  412.     hook->s.eType = ET_MISSILE;
  413.     hook->r.svFlags = SVF_USE_CURRENT_ORIGIN;
  414.     hook->s.weapon = WP_GRAPPLING_HOOK;
  415.     hook->r.ownerNum = self->s.number;
  416.     hook->methodOfDeath = MOD_GRAPPLE;
  417.     hook->clipmask = MASK_SHOT;
  418.     hook->parent = self;
  419.  
  420.     hook->s.pos.trType = TR_LINEAR;
  421.     hook->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME;        // move a bit on the very first frame
  422.     hook->s.otherEntityNum = self->s.number; // use to match beam in client
  423.     VectorCopy( start, hook->s.pos.trBase );
  424.     VectorScale( dir, 800, hook->s.pos.trDelta );
  425.     SnapVector( hook->s.pos.trDelta );            // save net bandwidth
  426.     VectorCopy (start, hook->r.currentOrigin);
  427.  
  428.     self->client->hook = hook;
  429.  
  430.     return hook;
  431. }
  432.  
  433.  
  434.  
  435.